home *** CD-ROM | disk | FTP | other *** search
/ CD ROM Paradise Collection 4 / CD ROM Paradise Collection 4 1995 Nov.iso / program / swagg_m.zip / MATH.SWG / 0026_Matrix Math.pas < prev    next >
Pascal/Delphi Source File  |  1993-08-27  |  4KB  |  124 lines

  1. {
  2. DJ MURDOCH
  3.  
  4. >The solution I use For dynamic Objects (I don't have any Complex code) is
  5. >to keep a counter in each matrix Record; every Function decrements the
  6. >counter, and when it reaches 0, disposes of the Object.  if you need to
  7. >use an Object twice, you increment the counter once before using it.
  8.  
  9. > if you allocate an Object twice, how do you get the first address back into
  10. > the Pointer Variable so it can be disposed?   I must not understand the
  11. > problem.  if I do:
  12.  
  13. > new(p); new(p);
  14.  
  15. > Unless I save the value of the first p, how can I dispose it?  And if I
  16. > save it, why not use two Pointer Variables, p1 and p2, instead?
  17.  
  18. You're right, there's no way to dispose of the first p^.  What I meant is
  19. something like this:  Suppose X and Y are Pointers to matrix Objects.  if I
  20. want to calculate Z as their product, and don't have any need For them any
  21. more, then it's fine if MatMul disposes of them in
  22.  
  23.   Z := MatMul(X,Y);
  24.  
  25. In fact, it's Really handy, because it lets me calculate X Y Z as
  26.  
  27.   W := MatMul(X, MatMul(Y,Z));
  28.  
  29. The problem comes up when I try to calculate something like X^2, because MatMul
  30. would get in trouble trying to dispose of X twice in
  31.  
  32.  Y := MatMul(X, X);
  33.  
  34. The solution I use is to keep a counter in every Object, and to follow a rigid
  35. discipline:
  36.  
  37.  1.  Newly created Objects (Function results) always have the counter set to
  38.      zero.
  39.  
  40.  2.  Every Function which takes a Pointer to one of these Objects as an
  41.      argument is sure to "touch" the Pointer, by passing it exactly once to
  42.      another Function.  (There's an exception below that lets you pass it more
  43.      than once if you need to.)
  44.  
  45. 3.   if a Function doesn't need to pass the Object to another Function, then
  46.      it passes it to the special Function "Touch()", to satisfy rule 2.
  47.      Touch checks the counter; if it's zero, it disposes of the Object,
  48.      otherwise, it decrements it by one.
  49.  
  50. 4.   The way to get around the "exactly once" rule 2 is to call the "Protect"
  51.      Function before you pass the Object.  This just increments the counter.
  52.  
  53. 5.   Functions should never change Objects being passed to them as arguments;
  54.      there's a Function called "Local" which makes a local copy to work on if
  55.      you need it.  What Local does is to check the counter; if it's zero,
  56.      Local just returns the original Object, otherwise it asks the Object to
  57.      make a copy of itself.
  58.  
  59. For example, to do the line above safely, I'd code it as
  60.  
  61.   Y := MatMul(X, Protect(X));
  62.  
  63. MatMul would look something like this:
  64. }
  65.  
  66. Function MatMul(Y, Z : PMatrix) : PMatrix;
  67. Var
  68.   result : PMatrix;
  69. begin
  70.   { Allocate result, fill in the values appropriately, then }
  71.   Touch(Y);
  72.   Touch(Z);
  73.   MatMul := result;
  74. end;
  75.  
  76. {
  77. The first Touch would just decrement the counter in X, and the second would
  78. dispose of it (assuming it wasn't already protected before the creation of Y).
  79.  
  80. I've found that this system works Really well, and I can sleep at night,
  81. knowing that I never leave dangling Pointers even though I'm doing lots of
  82. allocations and deallocations.
  83.  
  84. Here, in Case you're interested, is the Real matrix multiplier:
  85. }
  86.  
  87. Function MProd(x, y : PMatrix) : PMatrix;
  88. { Calculate the matrix product of x and y }
  89. Var
  90.   result  : PMatrix;
  91.   i, j, k : Word;
  92.   mp      : PFloat;
  93. begin
  94.   if (x = nil) or (y = nil) or (x^.cols <> y^.rows) then
  95.     MProd := nil
  96.   else
  97.   begin
  98.     result := Matrix(x^.rows, y^.cols, nil, True);
  99.     if result <> nil then
  100.       With result^ do
  101.       begin
  102.         For i := 1 to rows do
  103.           With x^.r^[i]^ do
  104.             For j := 1 to cols do
  105.             begin
  106.               mp := pval(i,j);
  107.               mp^ := 0;
  108.               For k := 1 to x^.cols do
  109.                 mp^ := mp^ + c[k] * y^.r^[k]^.c[j];
  110.             end;
  111.       end;
  112.     MProd := result;
  113.     Touch(x);
  114.     Touch(y);
  115.   end;
  116. end;
  117.  
  118. {
  119. As you can see, the memory allocation is a pretty minor part of it.  The
  120. dynamic indexing is Really ugly (I'd like to use "y[k,j]", but I'm stuck using
  121. "y^.r^[k]^.c[j]"), but I haven't found any way around that.
  122. }
  123.  
  124.